JPA Entity 설정하기
✒️ 2025-08-05 13:54 내용 수정
- 개인 프로젝트를 진행하면서 JPA Entity의 여러 Annotation에 대해 정리할 필요성을 느껴 이를 정리하였다.
- 아래 참고자료의 내용으로 글을 작성하였다.
1. Entity 지정
- 먼저 생성하려는 Entity 이름의 Java class를 생성하고,
@EntityAnnotation을 추가한다.- Entity의 이름은 기본 설정으로는 class이름과 동일하게 생성된다.
- 만약 이름을 변경하고 싶다면
@Entity(name="지정할이름")으로 수정할 수 있다.
- JavaBean과 DTO처럼 해당 클래스에는 아래 내용이 반드시 포함되어야 한다.
- 필드를
private로 설정하여 캡슐화를 해야 한다. - 기본 생성자를 반드시 추가해야 한다.
- 필드에 접근할 setter와 getter 메서드가 있어야 한다.
- 필드를
- 참고 자료에 따르면 다양한 JPA 구현체들이 기능을 제공하기 위해 Entity를 상속할 수 있기 때문에 Entity 클래스들의 접근 제어자는 final로 설정해서는 안된다고 한다.
import jakarta.persistence.*;
@Entity // Entity임을 명시
public class User {
@Id
private Long Id;
@Column
private String name;
public User() {}
public User(Long id, String name) {
this.id = id;
this.name = name;
}
public void setId(Long id) {this.id = id;}
public Long getId() {return this.id;}
public void setName(String name) {this.name = name;}
public String getName() {return this.name;}
}
- lombok을 사용할 경우 기본 생성자는
@NoArgsConstructor, getter와 setter는@Data나@Getter/@SetterAnnotation을 추가하여 코드를 간단하게 표현할 수 있다.
import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity // Entity임을 명시
@Data
@NoArgsConstructor
public class User {
@Id
private Long Id;
@Column
private String name;
public User(Long id, String name) {
this.id = id;
this.name = name;
}
}
2. Id 설정
- Entity에는 Primary key가 반드시 필요하며,
@IdAnnotation으로 설정할 수 있다. @GeneratedValueAnnotation은 Primary key를 생성할 때 특정 값들로 생성하도록 지정할 수 있는 Annotation이다.AUTO,TABLE,SEQUENCE,IDENTITY옵션을 설정하여 Primary key 생성 방법을 지정할 수 있다.- 참고 자료 : Geeksforgeeks Hibernate - GeneratedValue Annotation in JPA, Hrishi D's Spring Boot Annotation GeneratedValue
package com.mini.quiz.entity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
public class User {
@Id // 식별자 설정
@GeneratedValue(strategy = GenerationType.IDENTITY) // Primary key 생성 전략
private Long id;
}
@GeneratedValue의 생성 전략
AUTO: 기본 설정값이며, JPA의 기본 생성 전략이다.- 데이터베이스의 설정에 따라 primary key가 자동으로 생성된다.
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
IDENTITY: 사용하는 DB의 자동 생성 전략에 따르며, 자동 증가 열(auto-increment columns) 설정을 따른다.- MySQL, PostgreSQL 등과 같이 자동 증가 열 설정을 지원하는 DB에서 사용된다.
- MySQL의 경우
AUTO_INCREMENT에 해당한다.- Table 다루기 참고.
- MySQL의 경우
- MySQL, PostgreSQL 등과 같이 자동 증가 열 설정을 지원하는 DB에서 사용된다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
SEQUENCE: DB Sequence를 사용하여 생성하는 전략으로, DB의 Sequence 객체를 필요로 한다.- Oracle, PostgreSQL과 같이 Sequence를 지원하는 DB에서 사용된다.
- Sequence 이름을 지정할 때
@SequenceGeneratorAnnotation을 사용한다. - 이 설정을 사용 시 DB에도 Sequence가 필요하다.
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq_gen")
@SequenceGenerator(name = "user_seq_gen", sequenceName = "user_id_seq", allocationSize = 1)
private Long id;
TABLE: Primary key 생성에 사용되는 별개의 테이블을 사용하는 전략이다.- 다른 생성 전략보다는 효율이 낮을 수 있으며, 잘 사용되지 않는다.
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "user_table_gen")
@TableGenerator(name = "user_table_gen", table = "user_id_table",
pkColumnName = "id_key", pkColumnValue = "id_value", allocationSize = 1)
private Long id;
UUID: UUID(Universally Unique Indentifier)를 사용하여 primary key를 생성하는 전략이다.- 데이터베이스 전반에 걸친 유일성이 필요한 경우에 사용할 수 있다.
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private Long id;
3. Table 설정
- DB의 테이블 이름과 Entity의 이름이 다른 경우 둘을 매칭시키기 위해
@TableAnnotation을 사용한다. - 이 Annotation이 없다면 Table의 이름은 Entity의 이름은 같게 설정된다.
- 이름을 기준으로 데이터베이스에 Entity 이름과 같은 테이블이 존재하면 해당 테이블에 Mapping이 되고, 없는 경우엔 테이블을 새로 생성한다.
@Entity
@Data
@NoArgsConstructor
@Table(name="UserInfo", schema="Home") // DB의 Home 스키마의 UserInfo라는 테이블과 User Entity를 매칭
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
4. Column 설정
@ColumnAnnotation은 DB의 column과 Entity의 field를 매칭시킨다.- 옵션으로 Column에 대한 다양한 설정을 지정할 수 있다.
- Column의 기본값 설정에 대한 참고 자료 : baeldung's Default Column Values in JPA
- 이 자료에선 특히 여러가지 column의 기본값 설정 방법들, 각 방법들의 특성 및 null 지정에 따른 차이까지 나와있다.
- Column의 기본값 설정에 대한 참고 자료 : baeldung's Default Column Values in JPA
| 속성 | 설명 |
|---|---|
name |
Table의 특정 Column과 Entity의 field를 매칭 |
length |
column의 데이터 길이를 설정 |
unique |
해당 column의 unique 여부를 설정 제약조건 참고. |
nullable |
해당 column의 null 여부를 설정 |
@ColumnDefault |
테이블 생성 시 DDL에 작성될 column의 기본값을 설정 |
@ColumnDefault("defaultValue") |
테이블 생성 시 DDL에 작성될 column의 기본값을 설정 |
package com.mini.quiz.entity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 50, // 해당 column의 길이를 50으로 설정
nullable = false, // null을 허용하지 않도록 설정
unique = true) // 해당 column의 unique를 설정
private String email;
@Column(name = "username", // DB Table에서 username이라는 column과 매칭
length = 15, nullable = false, unique = true)
private String nickname;
@Column(nullable = false)
@ColumnDefault("false") // 해당 컬럼의 기본값을 false로 설정
private boolean blocked;
@Column(length = 100)
private String profile;
@Column(length = 30, nullable = false)
private String password;
@Column(nullable = false,
columnDefinition = "boolean default false") // 해당 컬럼의 기본값을 false로 설정
private boolean verified;
}
5. Entity 관계 설정
참고 자료 : Jonathan's Hibernate - OneToOne, OneToMany, ManyToOne and ManyToMany
- 엔티티(테이블) 간의
1:1,1:N,N:M관계를 표현하기 위한 Annotation을 필드(Column)에 추가한다.
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
@OneToOne
private UserProfile profile;
}
@Entity
public class UserProfile {
@Id
@GeneratedValue
private Long id;
private String address;
}
1) 1:1 관계
@OneToOne: 한 Entity가 오직 하나의 Entity와 연관될 때 사용한다.- 예시에서 사용자는 사용자 프로필 1개만 가질 수 있고, 사용자 프로필도 한 명의 사용자만 가질 수 있다.
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
// UserProfile과 연결
@OneToOne
private UserProfile profile;
}
@Entity
public class UserProfile {
@Id
@GeneratedValue
private Long id;
private String address;
}
- 두 테이블 중에 FK(Foreign Key)를 저장하는 테이블을 지정하여 연관 관계의 소유자를 지정할 수 있다.
- FK 테이블에 Mapping될 Entity에
mappedBy속성을 사용한다. - FK를 저장하는 테이블에
@JoinColumn을 적용한다. - 예시에서
UserEntity에profile_id이란 이름으로 FK를 저장할 때@JoinColumn(name = "profile_id")을User에,mappedBy를UserProfile에 설정했다.

@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
// profile_id를 저장
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "profile_id")
private UserProfile profile;
}
@Entity
public class UserProfile {
@Id
@GeneratedValue
private Long id;
private String address;
@OneToOne(
mappedBy = "userProfile",
CascadeType.all,
orphanRemoval = true
)
private User user;
}
2) 1:N, N:1 관계
@OneToMany: 하나의 Entity가 여러 개의 Entity와 연결되어 있을 때 사용하는 관계다.@ManyToOne: 여러 Entity가 하나의 Entity와 연결되어 있을 때 사용한다.- 예시에서 사용자는 여러 개의 주문 목록을 가질 수 있고(
1:N), 주문 목록은 하나의 사용자만 가질 수 있다(N:1). 1:N으로 Mapping 시List<>형태의 Collection 타입으로 선언한다.
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
@OneToMany
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@Id
@GeneratedValue
private Long id;
private String product;
@ManyToOne
private User user;
}
1:N,N:1관계에서 FK는 다수인 쪽의 테이블에서 저장한다.@JoinColumn은 FK를 저장하는 다수인 쪽의 테이블에 지정한다.mappedBy는 하나인 쪽의 테이블에 지정한다.- 연결된 다른 Entity의 인스턴스명 혹은 테이블 이름으로 작성해야 한다.
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
// Order의 user로 매핑됨
@OneToMany(mappedBy = "user")
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@Id
@GeneratedValue
private Long id;
private String product;
// user_id를 저장
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
3) N:M 관계
@ManyToMany: 여러 Entity가 다른 여러 Entity와 연결되어 있을 때 사용하는 관계다.M:N관계의 경우 중간 테이블이 자동으로 생성된다.- 추가 정보를 저장하거나 직접 제어가 어렵기 때문에 중간 테이블을 별도의 Entity로 분리하여
1:N,N:1관계로 설정하는 방법을 권장하고 있다.
- 추가 정보를 저장하거나 직접 제어가 어렵기 때문에 중간 테이블을 별도의 Entity로 분리하여
- 예시에서 사용자는 여러 개의 역할을 가질 수 있고, 역할도 여러 사람을 가질 수 있다.
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String username;
@ManyToMany
private Set<Role> roles = new HashSet<>();
}
@Entity
public class Role {
@Id @GeneratedValue
private Long id;
private String roleName;
@ManyToMany
private Set<User> users = new HashSet<>();
}
N:M관계에선mappedBy를 사용할 때 한 쪽 Entity에서만 설정해야 한다.- 관계의 주인은 하나만 존재하며, 이를 지키지 않으면 순환 참조 문제가 발생한다.
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String username;
// User에 Role의 필드 users로 연결됨을 명시
@ManyToMany(mappedBy = "users")
private Set<Role> roles = new HashSet<>();
}
@Entity
public class Role {
@Id @GeneratedValue
private Long id;
private String roleName;
@ManyToMany
private Set<User> users = new HashSet<>();
}
6. 연관 관계 로딩 전략(FetchType)
- 연관 관계를 설정한 Entity 간의 데이터를 불러오는 전략을 설정한다.
- 데이터를 가져오는 시점을 설정하여 애플리케이션 성능과 메모리 사용량 등 데이터 처리에 큰 영향을 줄 수 있다.
- 참고 자료 : Geeksforgeeks Hibernate - Eager/Lazy Loading
1) 지연 로딩(Lazy Loading)
- Hibernate의 기본 FetchType이다.
- 데이터를 처음부터 가져오는 것이 아닌 데이터에 실제 접근하는 시점에 불러오는 방식이다.
- 연관 설정된 Entity가 항상 필요한 상황이 아니거나, 참조해야 하는 Entity의 데이터가 많은 경우 성능 측면에 효과적인 전략이다.
- 연관 관계의 Entity를 가져올 때 추가적인 데이터베이스 query가 필요할 수도 있다.
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
// profile_id를 저장
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "profile_id")
private UserProfile profile;
}
2) 즉시 로딩(Eager Loading)
- 메인 Entity를 데이터베이스에서 가져올 때 연관 관계의 Entity를 바로 가져오는 방법이다.
- 연관 관계 데이터가 항상 필요한 경우 사용한다.
- 초기에 필요한 데이터를 모두 가져오기 때문에 성능 측면에서 Lazy-Loading보다 떨어질 수 있다.
- 하지만 데이터를 초기에 가져오기에 연관 관계 Entity 접근 시 필요한 반복적인 query가 줄어든다.
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
// profile_id를 저장
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "profile_id")
private UserProfile profile;
}
7. 영속성 전파 설정(Cascading)
- 참고 자료 : Geeksforgeeks Hibernate - Differenct Cascade Types
- Cascading : 폭포처럼 위에서 아래로 흐르는 현상
- CSS(Cascading Style Sheet)도 스타일을 위에서 아래로 내려주는 형식을 가진다.
- 연관 관계로 설정된 두 Entity에서 부모 Entity에 수행된 작업이 자식 Entity에도 적용되는 것을 의미한다.
- Cascading 설정을 적용하면 한 Entity에서 생긴 변화를 코드로 일일이 설정하는 대신 자동으로 적용할 수 있다.
save,update,delete,refresh동작이 부모 Entity에서 발생하면 자식 Entity에 어떤 방식으로 적용할 지 설정할 수 있다.
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
// 부모 Entity
@OneToMany(
mappedBy = "order",
cascade = CascadeType.ALL
)
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@Id
@GeneratedValue
private Long id;
private String product;
// 자식 Entity
// user_id를 저장
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
| 타입 | 설명 |
|---|---|
CascadeType.ALL |
모든 옵션을 적용PERSIST, MERGE, REMOVE, REFRESH, DETACH |
CascadeType.PERSIST |
PERSIST(save) 동작만 적용부모 Entity를 저장하면 자식 Entity도 자동 저장 |
CascadeType.MERGE |
MERGE(update) 동작만 적용부모 Entity를 수정/병합하면 자식 Entity에도 병합 |
CascadeType.REMOVE |
REMOVE(remove) 동작만 적용부모 Entity를 제거하면 자식 Entity도 제거 |
CascadeType.REFREST |
REFRESH 동작만 적용부모 Entity를 새로고침하면 자식 Entity도 최신 상태로 동기화 |
CascadeType.DETACH |
DETACH 동작만 적용부모 Entity가 비영속 상태가 되면 자식 Entity도 비영속 상태로 적용 |